package cn.com.twoke.application.game.mario.game.util;

import cn.com.twoke.application.game.mario.core.ecs.component.ColliderComponent;
import cn.com.twoke.application.game.mario.core.ecs.component.PositionComponent;
import cn.com.twoke.application.game.mario.core.ecs.entity.Entity;
import cn.com.twoke.application.game.mario.game.component.PipeComponent;
import cn.com.twoke.application.game.mario.game.component.TransfersComponent;
import cn.com.twoke.application.game.mario.game.config.Tiles;

import java.awt.*;
import java.util.function.Consumer;

public class PipeUtils {


    public static ColliderComponent of(Entity entity, Consumer<TransfersComponent.Transfer> addTransferHook) {
        if (entity.hasComponent(PipeComponent.class) && entity.hasComponent(PositionComponent.class)) {
            PositionComponent position = entity.getComponent(PositionComponent.class);
            PipeComponent pipe = entity.getComponent(PipeComponent.class);
            switch (pipe.type) {
                case VERTICAL:  return createVertical(entity, position, pipe, addTransferHook);
                case J_SHAPED: return  createJShaped(entity, position, pipe, addTransferHook);
            }
        }
        return null;
    }

    /**
     *         transfer.enabled = pipe.enableEntrance;
     *         transfer.type = pipe.transferType;
     *         transfer.setTargetSceneName(pipe.targetSceneName);
     *         transfer.setName(pipe.entryName);
     *         transfer.setCheckinFun(pipe.checkinFun);
     * @param entity
     * @param position
     * @param pipe
     * @param addTransferHook
     * @return
     */
    private static ColliderComponent createJShaped(Entity entity, PositionComponent position, PipeComponent pipe, Consumer<TransfersComponent.Transfer> addTransferHook) {
        TransfersComponent transfers = new TransfersComponent();
        TransfersComponent.Transfer transfer = transfers.createTransfer();
        transfer.direction = TransfersComponent.Direction.LEFT;
        transfer.shape = new Rectangle((int) position.x - Tiles.widthOf(1 + pipe.horizontalLength) - Tiles.scaleOf(2),
                (int) position.y + Tiles.heightOf(1 + pipe.verticalLength) + Tiles.scaleOf(2),
                    Tiles.scaleOf(2),
                Tiles.heightOf(2) - Tiles.scaleOf(4)
        );
        addTransferHook.accept(transfer);
        if (pipe.isEmbeddedWall) {
            entity.addComponent(transfers);


            pipe.addPipePart(PipeComponent.PipePartType.VERTICAL, new Rectangle(
                    (int)position.x,
                    (int)position.y,
                    Tiles.widthOf(1),
                    Tiles.heightOf( 1 + pipe.verticalLength)
            ));
            pipe.addPipePart(PipeComponent.PipePartType.ENTRY_LEFT, new Rectangle(
                    (int)position.x - Tiles.widthOf(1 + pipe.horizontalLength),
                    (int)position.y + Tiles.heightOf(1 + pipe.verticalLength),
                    Tiles.widthOf(1),
                    Tiles.heightOf( 2)
            ));
            pipe.addPipePart(PipeComponent.PipePartType.HORIZONTAL, new Rectangle(
                    (int)position.x - Tiles.widthOf( pipe.horizontalLength),
                    (int)position.y + Tiles.heightOf(1 + pipe.verticalLength),
                    Tiles.widthOf(pipe.horizontalLength),
                    Tiles.heightOf( 2)
            ));

            pipe.addPipePart(PipeComponent.PipePartType.LEFT_JOINT, new Rectangle(
                    (int)position.x,
                    (int)position.y + Tiles.heightOf(1 + pipe.verticalLength),
                    Tiles.widthOf(1),
                    Tiles.heightOf( 2)
            ));

            return new ColliderComponent(() -> {
                Polygon polygon = new Polygon();
                polygon.addPoint((int) position.x + Tiles.scaleOf(2), (int) position.y);
                polygon.addPoint((int) position.x + Tiles.widthOf(1), (int) position.y);
                polygon.addPoint((int) position.x + Tiles.widthOf(1),(int) position.y + Tiles.heightOf(3 + pipe.verticalLength ));
                polygon.addPoint((int) position.x + Tiles.scaleOf(2), (int) position.y + Tiles.heightOf(3 + pipe.verticalLength));
                polygon.addPoint((int) position.x + Tiles.scaleOf(2), (int) position.y + Tiles.heightOf(3 + pipe.verticalLength) - Tiles.scaleOf(2));
                polygon.addPoint((int) position.x - Tiles.scaleOf(2) - Tiles.widthOf(pipe.horizontalLength), (int) position.y + Tiles.heightOf(3 + pipe.verticalLength) - Tiles.scaleOf(2));
                polygon.addPoint((int) position.x - Tiles.scaleOf(2) - Tiles.widthOf(pipe.horizontalLength), (int) position.y + Tiles.heightOf(3 + pipe.verticalLength));
                polygon.addPoint((int) position.x - Tiles.widthOf(1 + pipe.horizontalLength), (int) position.y + Tiles.heightOf(3 + pipe.verticalLength));
                polygon.addPoint((int) position.x - Tiles.widthOf(1 + pipe.horizontalLength), (int) position.y + Tiles.heightOf(1 + pipe.verticalLength));
                polygon.addPoint((int) position.x - Tiles.scaleOf(2) - Tiles.widthOf( pipe.horizontalLength), (int) position.y + Tiles.heightOf(1 + pipe.verticalLength));
                polygon.addPoint((int) position.x - Tiles.scaleOf(2) - Tiles.widthOf(pipe.horizontalLength), (int) position.y + Tiles.heightOf(1 + pipe.verticalLength));
                polygon.addPoint((int) position.x - Tiles.scaleOf(2) - Tiles.widthOf(pipe.horizontalLength), (int) position.y + Tiles.heightOf(1 + pipe.verticalLength) + Tiles.scaleOf(2));
                polygon.addPoint((int) position.x + Tiles.scaleOf(2), (int) position.y + Tiles.heightOf(1 + pipe.verticalLength) + Tiles.scaleOf(2));
                polygon.addPoint((int) position.x + Tiles.scaleOf(2), (int) position.y);
                return polygon;
            });
        } else {
            transfer = transfers.createTransfer();
            transfer.direction = TransfersComponent.Direction.TOP;
            transfer.shape = new Rectangle((int) position.x + Tiles.scaleOf(2),
                    (int) position.y - Tiles.scaleOf(2),
                    Tiles.widthOf(2) - Tiles.scaleOf(4),
                    Tiles.scaleOf(2)
            );
            addTransferHook.accept(transfer);
            entity.addComponent(transfers);
            pipe.addPipePart(PipeComponent.PipePartType.ENTRY_TOP, new Rectangle(
                    (int)position.x,
                    (int)position.y,
                    Tiles.widthOf(2),
                    Tiles.heightOf(1)));
            pipe.addPipePart(PipeComponent.PipePartType.VERTICAL, new Rectangle(
                    (int)position.x,
                    (int)position.y + Tiles.heightOf(1),
                    Tiles.widthOf(2),
                    Tiles.heightOf( pipe.verticalLength)
            ));
            pipe.addPipePart(PipeComponent.PipePartType.ENTRY_LEFT, new Rectangle(
                    (int)position.x - Tiles.widthOf(1 + pipe.horizontalLength),
                    (int)position.y + Tiles.heightOf(pipe.verticalLength),
                    Tiles.widthOf(1),
                    Tiles.heightOf( 2)
            ));
            pipe.addPipePart(PipeComponent.PipePartType.HORIZONTAL, new Rectangle(
                    (int)position.x - Tiles.widthOf( pipe.horizontalLength),
                    (int)position.y + Tiles.heightOf( pipe.verticalLength),
                    Tiles.widthOf(pipe.horizontalLength),
                    Tiles.heightOf( 2)
            ));

            pipe.addPipePart(PipeComponent.PipePartType.LEFT_JOINT, new Rectangle(
                    (int)position.x,
                    (int)position.y + Tiles.heightOf( pipe.verticalLength),
                    Tiles.widthOf(2),
                    Tiles.heightOf( 2)
            ));

            return new ColliderComponent(() -> {
                Polygon polygon = new Polygon();
                polygon.addPoint((int) position.x,(int) position.y);
                polygon.addPoint((int) position.x + Tiles.widthOf(2),(int) position.y +  0);
                polygon.addPoint((int) position.x  + Tiles.widthOf(2),(int) position.y + Tiles.heightOf(1) - Tiles.scaleOf(2));
                polygon.addPoint((int) position.x + Tiles.widthOf(2) - Tiles.scaleOf(2),(int) position.y + Tiles.heightOf(1) - Tiles.scaleOf(2));
                polygon.addPoint((int) position.x + Tiles.widthOf(2) - Tiles.scaleOf(2),(int) position.y + Tiles.heightOf(3 + pipe.verticalLength ));
                polygon.addPoint((int) position.x + Tiles.scaleOf(2), (int) position.y + Tiles.heightOf(3 + pipe.verticalLength));
                polygon.addPoint((int) position.x + Tiles.scaleOf(2), (int) position.y + Tiles.heightOf(3 + pipe.verticalLength) - Tiles.scaleOf(2));
                polygon.addPoint((int) position.x - Tiles.scaleOf(2) - Tiles.widthOf(pipe.horizontalLength), (int) position.y + Tiles.heightOf(3 + pipe.verticalLength) - Tiles.scaleOf(2));
                polygon.addPoint((int) position.x - Tiles.scaleOf(2) - Tiles.widthOf(pipe.horizontalLength), (int) position.y + Tiles.heightOf(3 + pipe.verticalLength));
                polygon.addPoint((int) position.x - Tiles.widthOf(1 + pipe.horizontalLength), (int) position.y + Tiles.heightOf(3 + pipe.verticalLength));
                polygon.addPoint((int) position.x - Tiles.widthOf(1 + pipe.horizontalLength), (int) position.y + Tiles.heightOf(1 + pipe.verticalLength));
                polygon.addPoint((int) position.x - Tiles.scaleOf(2) - Tiles.widthOf( pipe.horizontalLength), (int) position.y + Tiles.heightOf(1 + pipe.verticalLength));
                polygon.addPoint((int) position.x - Tiles.scaleOf(2) - Tiles.widthOf(pipe.horizontalLength), (int) position.y + Tiles.heightOf(1 + pipe.verticalLength));
                polygon.addPoint((int) position.x - Tiles.scaleOf(2) - Tiles.widthOf(pipe.horizontalLength), (int) position.y + Tiles.heightOf(1 + pipe.verticalLength) + Tiles.scaleOf(2));
                polygon.addPoint((int) position.x + Tiles.scaleOf(2), (int) position.y + Tiles.heightOf(1 + pipe.verticalLength) + Tiles.scaleOf(2));
                polygon.addPoint((int) position.x + Tiles.scaleOf(2), (int) position.y + Tiles.heightOf(1) - Tiles.scaleOf(2));
                polygon.addPoint((int) position.x + 0, (int) position.y + Tiles.heightOf(1) - Tiles.scaleOf(2));
                polygon.addPoint((int) position.x + 0, (int) position.y + 0);
                return polygon;
            });
        }


    }

    private static ColliderComponent createVertical(Entity entity, PositionComponent position, PipeComponent pipe, Consumer<TransfersComponent.Transfer> addTransferHook) {
        TransfersComponent transfers = new TransfersComponent();
        TransfersComponent.Transfer transfer = transfers.createTransfer();
        transfer.direction = TransfersComponent.Direction.TOP;
        transfer.shape = new Rectangle((int) position.x + Tiles.scaleOf(2),
                (int) position.y - Tiles.scaleOf(2),
                Tiles.widthOf(2) - Tiles.scaleOf(4),
                Tiles.scaleOf(2)
        );
        addTransferHook.accept(transfer);
        entity.addComponent(transfers);


        pipe.addPipePart(PipeComponent.PipePartType.ENTRY_TOP, new Rectangle(
                (int)position.x,
                (int)position.y,
                Tiles.widthOf(2),
                Tiles.heightOf(1)));
        pipe.addPipePart(PipeComponent.PipePartType.VERTICAL, new Rectangle(
                (int)position.x,
                (int)position.y + Tiles.heightOf(1),
                Tiles.widthOf(2),
                Tiles.heightOf( pipe.verticalLength)
        ));

        return new ColliderComponent(() -> {
            Polygon polygon = new Polygon();
            polygon.addPoint((int) position.x,(int) position.y);
            polygon.addPoint((int) position.x + Tiles.widthOf(2),(int) position.y +  0);
            polygon.addPoint((int) position.x  + Tiles.widthOf(2),(int) position.y + Tiles.heightOf(1) - Tiles.scaleOf(2));
            polygon.addPoint((int) position.x + Tiles.widthOf(2) - Tiles.scaleOf(2),(int) position.y + Tiles.heightOf(1) - Tiles.scaleOf(2));
            polygon.addPoint((int) position.x + Tiles.widthOf(2) - Tiles.scaleOf(2),(int) position.y + Tiles.heightOf(1 + pipe.verticalLength));
            polygon.addPoint((int) position.x + Tiles.scaleOf(2), (int) position.y + Tiles.heightOf(1 + pipe.verticalLength));
            polygon.addPoint((int) position.x + Tiles.scaleOf(2), (int) position.y + Tiles.heightOf(1) - Tiles.scaleOf(2));
            polygon.addPoint((int) position.x + 0, (int) position.y + Tiles.heightOf(1) - Tiles.scaleOf(2));
            polygon.addPoint((int) position.x + 0, (int) position.y + 0);




            return polygon;
        });
    }


}
